package com.example.mqsender.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.mqsender.MQEventSender;
import com.example.mqsender.annotation.SyncIDic;
import enums.EventTypeEnum;
import enums.OperateTypeEnum;
import event.BusinessDataInfoEvent;
import event.BusinessEvent;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Method;

/**
 * @author ke
 * Created by on  2021-05-28 09:42
 */
@Aspect
@Slf4j
@EnableAsync
@Component
public class SyncSenderData {

    @Autowired
    private MQEventSender dicEventSender;

    @Pointcut("@annotation(com.example.mqsender.annotation.SyncIDic)")
    public void logPointCut() {

    }

    /**
     * 后置通知（捕获新增、回调、提交）
     *
     * @param p
     * @param returnValue
     */
    @AfterReturning(value = "logPointCut()", returning = "returnValue")
    public void logAfter(final JoinPoint p, final Object returnValue) {
        syncData(p, returnValue);
    }

    /**
     * 异步同步 新增、修改、删除数据到配码服务
     *
     * @param
     * @return void
     * @author ke
     * @date 2021-05-28
     */
    @Async
    public void syncData(final JoinPoint joinPoint, Object returnValue) {
        BusinessEvent dicEvent = new BusinessDataInfoEvent();
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            SyncIDic syncIDic = method.getAnnotation(SyncIDic.class);
            OperateTypeEnum operateTypeEnum = syncIDic.operate();
            EventTypeEnum eventTypeEnum = syncIDic.event();

            if (operateTypeEnum.equals(OperateTypeEnum.DELETE)) {
                setDataInfo(joinPoint, joinPoint.getArgs()[0], dicEvent);
            } else if (operateTypeEnum.equals(OperateTypeEnum.UPDATE)) {
                setDataInfo(joinPoint, joinPoint.getArgs()[0], dicEvent);
            }else{
                setDataInfo(joinPoint, returnValue, dicEvent);
            }
            dicEvent.setOperateType(operateTypeEnum);
            dicEvent.setEventType(eventTypeEnum);
            dicEventSender.send(dicEvent);
            log.info("RabbitMQ推送消息：{}", JSON.toJSON(dicEvent));
        } catch (Exception e) {
            e.printStackTrace();
            log.info("RabbitMQ推送消息异常：{} ，{}", JSON.toJSON(dicEvent), e.getMessage());
        }
    }
    /**
    * 新增，修改，删除  设置属性值
    *
    * @param joinPoint
    * @param value
    * @param dicEvent
    * @return void
    * @author ke
    * @date 2021-05-28
    */
    private void setDataInfo(JoinPoint joinPoint, Object value, BusinessEvent dicEvent) throws Exception {
        if (!ObjectUtils.isEmpty(value)) {
            String json = JSON.toJSONString(value);
            JSONObject jsonObject = JSON.parseObject(json);
            if (jsonObject.containsKey("id")) {
                Long id = jsonObject.getLong("id");
                //TODO AOP切面对应的切入点
                //TODO 此处注释的是，基于MybatisPlus生成的基类ServiceImpl，通过反射调用目标对象对应的getById方法获取新增，修改，删除的数据
                //TODO 可根据具体的业务场景进行通用抽取
                /*Object target = joinPoint.getTarget();
                Method targetMethod = target.getClass().getSuperclass().getMethod("getById", Serializable.class);
                Object result = targetMethod.invoke(target, id);

                Field declaredField = result.getClass().getDeclaredField("code");
                declaredField.setAccessible(true);
                dicEvent.setBusinessId(declaredField.get(result).toString());*/
                dicEvent.setBusinessId(id.toString());
                dicEvent.setData(JSON.toJSONString(value));
            }

        }
    }
}
